#include "mysql_conn.h"
#include <stdio.h>
#include <sstream>
#include "logging.h"


bool mysql_conn::connect(mysql_conn* conn, const std::string& ip, const std::string& user, const std::string& pwd, const std::string& db, const unsigned short port)
{
	conn->setConfig(ip, user, pwd, db, port);
	return conn->connect();
}

mysql_conn::mysql_conn()
{
	m_queryRes = NULL;
	m_field = NULL;
	MYSQL *mysql = mysql_init(&m_mysql);

	if (!mysql)
	{
		LOGE("Call mysql_init call failed");
	}
}

mysql_conn::~mysql_conn()
{
	if (m_queryRes)
		mysql_free_result(m_queryRes);
	mysql_close(&m_mysql);
}

///////////////////////////////////////////////////////////////////////////////
// Connector::connect
///////////////////////////////////////////////////////////////////////////////
bool mysql_conn::connect()
{
	MYSQL *mysql = mysql_real_connect(&m_mysql, _host.c_str(), _user.c_str(), _passwd.c_str(), _db.c_str(), _port, NULL, 0);

	if (mysql)
	{
		LOGI("Connect to mysql [ %s:%d==>%s ] succeed", _host, _port, _db);
		// Set the utf8 query charset
		int ret = mysql_real_query(&m_mysql, "set NAMES'utf8'", (unsigned int)strlen("set NAMES'utf8'"));
		if (ret)
		{
			int qerrno = mysql_errno(&m_mysql);
			LOGE("Set utf8 query charset failed, error ==> [ %d ]", qerrno);
		}
	}
	else
	{
		LOGE("Connect to mysql [ %s:%d==>%s ] failed, error ==> [ %d ]", _host, _port, _db, mysql_errno(&m_mysql));

		return false;
	}
	return true;
}

///////////////////////////////////////////////////////////////////////////////
// Connector::lockTable
///////////////////////////////////////////////////////////////////////////////
bool mysql_conn::lockTable(const char* table, const char* priority)
{
	std::ostringstream oss;
	oss << "LOCK TABLES " << table << " " << priority;
	if (mysql_query(&m_mysql, oss.str().c_str()))
		return false;
	return true;
}

///////////////////////////////////////////////////////////////////////////////
// Connector::unlockTable
///////////////////////////////////////////////////////////////////////////////
bool mysql_conn::unlockTable()
{
	if (mysql_query(&m_mysql, "UNLOCK TABLES"))
		return true;
	return false;
}


///////////////////////////////////////////////////////////////////////////////
// Connector::query
///////////////////////////////////////////////////////////////////////////////
bool mysql_conn::query(const char *sql)
{
	auto real_query = [this](const char* sql)
	{
		int qerrno = mysql_real_query(&m_mysql, sql, strlen(sql));
		if (qerrno)
		{
			errno = mysql_errno(&m_mysql);
			LOGE("Query [ %s ] call failed, error ==> [ %d ]", sql, qerrno);
		}
		return qerrno;
	};
	int qerrno = real_query(sql);
	if (!qerrno)
		return true;

	if (CR_SERVER_GONE_ERROR != qerrno) // MYSQL server timeout
		return false;

	LOGT("Trying to connect the server again..");
	if (!connect())
		return false;

	qerrno = real_query(sql);
	if (!qerrno)
		return true;
	return false;
}

///////////////////////////////////////////////////////////////////////////////
// Connector::getRes
///////////////////////////////////////////////////////////////////////////////
MYSQL_RES* mysql_conn::genRes()
{
	if (m_queryRes)
		mysql_free_result(m_queryRes);

	m_queryRes = mysql_store_result(&m_mysql);
	if (!m_queryRes)
	{
		LOGE("Call mysql_store_result failed");
		return NULL;
	}
	return m_queryRes;
}

///////////////////////////////////////////////////////////////////////////////
// Connector::getRes
///////////////////////////////////////////////////////////////////////////////
bool mysql_conn::isResEmpty()
{
	if (!genRes())
		return true;

	return !m_queryRes->row_count;
}

MYSQL* mysql_conn::get_mysql()
{
	return &m_mysql;
}

bool mysql_conn::connected()
{
	int qerrno = mysql_errno(&m_mysql);
	if (qerrno == CR_SERVER_GONE_ERROR) // MYSQL server timeout
	{
		return false;
	}
	return true;
}

void mysql_conn::setConfig(const std::string& ip, const std::string& user, const std::string& pwd, const std::string& db, const int port)
{
	_host = ip;
	_user = user;
	_passwd = pwd;
	_db = db;
	_port = port;
}
